﻿#pragma comment(lib, "dbghelp.lib")
#include <iostream>
#include <thread>
#include <deque>
#include <mutex>
#include <boost/asio.hpp>

#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>

#include <atomic>
#include <functional>
#include <queue>
#include <cstdlib>
#include <ctime>
#include <thread>
#include <chrono>
#include <condition_variable>
#include "interface/AllInterface.h"
#include "recommend/Recommend.h"
#include "item/ItemUtil.h"


using namespace std;

using tcp = boost::asio::ip::tcp;
namespace http = boost::beast::http;
namespace net = boost::asio;
using namespace boost::asio;
#if __cplusplus < 201402L
namespace std {
    template<typename T, typename... Args>
    std::unique_ptr<T> make_unique(Args&&... args) {
         return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
    }
}
#endif

// 请求池类
class RequestPool {
public:
    // 添加请求到池中
    void addRequest(unique_ptr<Request> request) {
        std::lock_guard<std::mutex> lock(mutex_);
        requests_.push_back(std::move(request));
    }

    // 从池中获取请求
    unique_ptr<Request> getRequest() {
        std::lock_guard<std::mutex> lock(mutex_);
        if (!requests_.empty()) {
            unique_ptr<Request> request(std::move(requests_.front()));
            requests_.pop_front();
            return request;
        }
        return nullptr;
    }

    bool empty() {
        return requests_.empty();
    }

private:
    deque<unique_ptr<Request> > requests_;
    mutex mutex_;
};

//global variables
int ItemUtil::Item::count_ = 0;
int ItemUtil::LinkedItems::count_ = 0;
int ItemUtil::LinkedItemsList::count_ = 0;
RequestPool* pool = new RequestPool();
const int thread_size = 2;
RecommendFactory rf(thread_size);
map<string, ItemUtil::LinkedItemsList*>* gMap = ItemUtil::load_items();
std::mutex mtx;
std::condition_variable cv;

std::string get_url_parameter(const std::string& uri, const std::string& param_name) {
    std::size_t param_start = uri.find('?');
    if (param_start == std::string::npos) {
        // 没有找到参数部分
        return "-1";
    }

    std::size_t param_end = uri.find('#', param_start);
    if (param_end == std::string::npos) {
        param_end = uri.length();
    }

    std::size_t param_pos = uri.find(param_name + '=', param_start);
    if (param_pos != std::string::npos && param_pos < param_end) {
        std::size_t value_start = param_pos + param_name.length() + 1;
        std::size_t value_end = uri.find('&', value_start);
        if (value_end == std::string::npos || value_end > param_end) {
            value_end = param_end;
        }
        return uri.substr(value_start, value_end - value_start);
    }

    return "-1";
}

void acceptRequestFunc() {

    io_context io_context;
    ip::tcp::acceptor acceptor(io_context, ip::tcp::endpoint(ip::tcp::v4(), 8088));
    while (true) {
        
        ip::tcp::socket *socket=new tcp::socket(io_context);
        // 等待并接受连接
        acceptor.accept(*socket);
        cout << "ready to accept socket" << endl;
        
        http::request<http::string_body> request;
        boost::beast::flat_buffer buffer;
        try {
            boost::beast::http::read(*socket, buffer, request);
        }
        catch (const std::exception& e) {
            std::cerr << "发生异常：" << e.what() << std::endl;
            delete socket;
            continue;
        }
        std::string uri(request.target().data(), request.target().size()); 
        uint16_t uid = std::stoi( get_url_parameter( uri, "uid") );
        uint16_t pos = std::stoi(get_url_parameter(uri, "pos"));
        
        std::unique_ptr<Request> ptr = std::make_unique<Request>();
        std::unique_ptr<tcp::socket> p (move(socket));
        ptr->socket_ptr=move(p);
        ptr->uid_ = uid;
        ptr->pos_ = pos;
        std::lock_guard<std::mutex> lock(mtx);
        pool->addRequest(move(ptr));
        cout << "add one Request" << endl;
        cv.notify_one();
        
    }

    

    // 运行 IO 上下文
    //io_context.run();
}

std::string make_http_response(vector<ItemUtil::Item*>* mids) {
    stringstream ss;
    std::string response = "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: " +
         std::to_string(8) + "\r\n" + //+ ss.str()+
        "Connection: close\r\n\r\n";
    cout << response << endl;
    return response;
}
void recommend(unique_ptr<Request> rp,int i) {
    RecommendInterface* ri = rf.getRecommendSys(i);
    shared_ptr<Request> rp2 = move(rp);
    vector<ItemUtil::Item*>* mids = ri->recommend(rp2,gMap);
    

    //// 发送响应
    write(*rp2->socket_ptr, buffer(make_http_response(mids)));
}


void proceeRequest(int i) {


    while (true) {
        std::unique_lock<std::mutex> lock(mtx);
        cv.wait(lock, [] { return !pool->empty(); });
        unique_ptr<Request> rp = pool->getRequest();
        recommend(move(rp), i);
    }
}



int main() {
    
	//启动接收请求线程
    std::thread t1(acceptRequestFunc);
    //acceptRequestFunc();
    std::this_thread::sleep_for(std::chrono::microseconds(10));
    //启动处理请求线程
    
    thread p1[thread_size];
    for (int i = 0; i < thread_size; i++) {
        p1[i]=thread(proceeRequest,i);
    }
    
    for (int i = 0; i < thread_size; i++) {
        p1[i].join();
    }
    t1.join();

    return 0;
    

    //return main2(argc, argv);

}
